package com.breeze.components.redis.cluster.id;

import cn.hutool.core.lang.Snowflake;
import com.breeze.components.core.enums.UniqueIdEnum;
import com.breeze.components.core.util.BitUtil;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RAtomicLong;
import org.redisson.api.RedissonClient;

/**
 * 分布式id工具
 *
 * @author breeze
 */
@Slf4j
public class SnowIdUtil {

  private static final int MAX_WORK_DATA_MOD = 1 << 10;
  private static final Map<UniqueIdEnum, Snowflake> CACHE_MAP = new ConcurrentHashMap<>();
  private static Snowflake COMMON;
  private static Integer WORK_ID;
  private static Integer DATA_ID;

  @Resource RedissonClient redissonClient;

  @SneakyThrows
  public static Snowflake getPut(UniqueIdEnum idEnum) {
    Snowflake snowflake = CACHE_MAP.get(idEnum);
    if (snowflake != null) {
      return snowflake;
    }
    //noinspection SynchronizationOnLocalVariableOrMethodParameter
    synchronized (idEnum) {
      snowflake = CACHE_MAP.get(idEnum);
      if (snowflake != null) {
        return snowflake;
      }
      while (WORK_ID == null || DATA_ID == null) {
        log.info("等待注入 workId {} dataId {}", WORK_ID, DATA_ID);
        TimeUnit.MILLISECONDS.sleep(50);
      }
      snowflake = new Snowflake(WORK_ID, DATA_ID);
      CACHE_MAP.putIfAbsent(idEnum, snowflake);
      return snowflake;
    }
  }

  public static Snowflake getCommonSnowId() {
    return COMMON;
  }

  @PostConstruct
  public void run() {
    RAtomicLong workId = redissonClient.getAtomicLong("ID_WORK_ID");
    long get = workId.addAndGet(1);
    int mod = Math.toIntExact(get % MAX_WORK_DATA_MOD);
    DATA_ID = BitUtil.getHeight(mod, 5);
    WORK_ID = BitUtil.getLow(mod, 5);
    log.info("当前机器：DATA_ID={}，WORK_ID={}", DATA_ID, WORK_ID);
    COMMON = new Snowflake(WORK_ID, DATA_ID);
  }
}
